package com.zp.ojcodesandbox;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ArrayUtil;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Volume;
import com.github.dockerjava.core.DockerClientBuilder;
import com.zp.ojcodesandbox.model.ExecuteCodeRequest;
import com.zp.ojcodesandbox.model.ExecuteCodeSandResponse;
import com.zp.ojcodesandbox.model.ExecuteMessage;
import com.zp.ojcodesandbox.util.InitEnvirment;
import com.zp.ojcodesandbox.util.ProcessRunAndMessage;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DockerSandBoxCpp extends CodeSandeBoxTemplate implements CodeSandBox{

    public static void main(String[] args){
        DockerSandBoxCpp dockerCodeSandBox= new DockerSandBoxCpp();
        //      DockerCodeSandBoxOld javaNativeCodeSandBox = new DockerCodeSandBoxOld();
        ExecuteCodeRequest executeCodeRequest = new ExecuteCodeRequest();
        executeCodeRequest.setInputs(Arrays.asList("3 4","1 2"));
        String code = ResourceUtil.readStr("testCode/test.cpp", StandardCharsets.UTF_8);
        executeCodeRequest.setCode(code);
        executeCodeRequest.setLanguage("cpp");
        ExecuteCodeSandResponse executeCodeSandResponse =
        dockerCodeSandBox.executeCode(executeCodeRequest);
        System.out.println(executeCodeSandResponse);
    }

    public static String codeDispose(String s){
        int t = s.indexOf("int main()");
        if(t == -1){
            return s;
        }
        for(int i = t; i < s.length(); i++){
            if(s.charAt(i) == '{'){
                StringBuilder resStr = new StringBuilder(s);
                resStr.insert(i + 1, "\n" + "freopen(\"app"+ File.separator+ "in.txt\", \"r\", stdin);");
                return resStr.toString();
            }
        }
        return s;
    }


    public ExecuteMessage compliedFile(DockerClient dockerClient, String containerId){
        // g++ app\Main.cpp -o app\Main.o
        String[] compiledCmd = ArrayUtil.append(new String[]{"g++", "app" + File.separator + CodeSandeBoxTemplate.Define_cpp_class_Name, "-o", "app" + File.separator + "Main.o"});
        ExecuteMessage executeMessage = ProcessRunAndMessage.dockerExecute(dockerClient, compiledCmd, "编译", containerId, false);
        return  executeMessage;
    }

    public List<ExecuteMessage> runFile(DockerClient dockerClient, String containerId, List<String> inputs, String userCodePath){
        List<ExecuteMessage> executeMessageList = new ArrayList<>();
        ExecuteMessage executeMessage;
        for(String input: inputs){
            //String[] inputArgs = input.split(" ");
            // 将输入信息写入文件
            FileUtil.writeString(input, userCodePath + File.separator + "in.txt", StandardCharsets.UTF_8);
            String[] runCmd = ArrayUtil.append(new String[]{ "app" + File.separator + "Main.o"});
            executeMessage = ProcessRunAndMessage.dockerExecute(dockerClient, runCmd, "运行", containerId, true);
            executeMessageList.add(executeMessage);
        }
        return  executeMessageList;
    }

    /**
     *
     * @param executeCodeRequest
     * @return
     */
    @Override
    public ExecuteCodeSandResponse executeCode(ExecuteCodeRequest executeCodeRequest) {


        List<String> inputs = executeCodeRequest.getInputs();
        String code = executeCodeRequest.getCode();
        String language = executeCodeRequest.getLanguage();
        // 先对代码进行处理
        code = codeDispose(code);

        // 搜索具有指定名称的公共属性
        File userCodeFile = super.createFile(code, language);
        String userCodeDir = userCodeFile.getParent();

        // docker 运行程序
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();
        /**
         * 创建容器并将java文件放入
         */
        // 初始化环境
        // 创建容器
        String image = InitEnvirment.CPP_IMAGE;

        // 创建容器
        CreateContainerResponse createContainerResponse = dockerCreateContainer(userCodeDir, dockerClient, image);
        String containerId = createContainerResponse.getId();

        // 开启容器
        dockerClient.startContainerCmd(containerId).exec();

        // 编译
        List<ExecuteMessage> executeMessageList = new ArrayList<>();
        ExecuteMessage executeMessage = this.compliedFile(dockerClient, containerId);

        // 加上对文件的读写权限
//        String[] chmodCmd = ArrayUtil.append(new String[]{"chmod", "777", "/app/Main.o"});
//        ProcessRunAndMessage.dockerExecute(dockerClient, chmodCmd, "权限", containerId, false);

        //编译无问题执行下一步
        if(executeMessage.getErrorMessage() == null || executeMessage.getErrorMessage().isEmpty()){
            // 执行
            executeMessageList = this.runFile(dockerClient, containerId, inputs, userCodeDir);
        }else {
            executeMessageList.add(executeMessage);
            ExecuteCodeSandResponse executeCodeSandResponse = super.jointMessage(executeMessageList);
            super.deleteFile(userCodeFile);
            super.deleteDocker(dockerClient, containerId);
            return executeCodeSandResponse;
        }

        super.deleteFile(userCodeFile);
        super.deleteDocker(dockerClient, containerId);
        ExecuteCodeSandResponse executeCodeSandResponse = super.jointMessage(executeMessageList);
        executeCodeSandResponse.setLanguage(executeCodeRequest.getLanguage());


        return executeCodeSandResponse;
    }

}
